/*
 *  ME218_work.c
 *  ArduinoOnXcode
 *
 *  Created by Rick Miley on 3/17/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include <ME218_work.h>

// variable
static void	(*RICKY_onSlaveTransmit)(void);

// prototype
void RICKY_attachSlaveTxEvent( void (*)(void) );

// routine

//unsigned long value asm("clock") = 3686400;
// You can specify a different name for the assembler code by using a special form of the asm statement:
// By default AVR-GCC uses the same symbolic names of functions or variables in C and assembler code.
// http://www.nongnu.org/avr-libc/user-manual/inline_asm.html#c_names_in_asm
//The assembler instruction, "clr r3", will clear the variable counter. 
//AVR-GCC will not completely reserve the specified register. 
//If the optimizer recognizes that the variable will not be referenced 
//any longer, the register may be re-used. But the compiler is not able 
//to check wether this register usage conflicts with any predefined register. 
//If you reserve too many registers in this way, 
//the compiler may even run out of registers during code generation.

//In order to change the name of a function, you need a prototype declaration, 
//because the compiler will not accept the asm keyword in the function definition:

//extern long Calc(void) asm ("CALCULATE");

//Calling the function Calc() will create assembler instructions to call the function CALCULATE.

void RICKY_onRequestService(void) {
	register unsigned char MIDI_shift asm("r3");

//	MIDI_shift=-1;	
	asm volatile("clr r3");


}

// assignment
void RICKY_attachSlaveTxEvent( void (*function)(void) )
{
	RICKY_onSlaveTransmit = function;
}

// initialization
//	RICKY_attachSlaveTxEvent(RICKY_onRequestService);



/******************************************************************************
 * User API 
 ******************************************************************************/

void ClearMeggy (void) {
int i,j, temp;
	
//	RICKY_attachSlaveTxEvent(RICKY_onRequestService);
// RICKY_attachSlaveTxEvent(__vector__RICKY);
	

for (i=0; i<8; i++)
{ 
	for (j=0; j<8; j++) {
		OffScreenGameSlate[i][j]=0;
	}
	
}
}



/* 
 void SoundCheck(void)   
 { 
 // Obsolete with current version of library; sounds stop automatically.
 // If your program contains "SoundCheck();" somewhere, please remove it.
 }
 */  


// Begin sound 
void  StartTone(unsigned int Tone, unsigned int duration)   
{
	OCR1A = Tone;
	//SoundState(1);
	ToneTimeRemaining = duration;  
}


unsigned char GetPixelR(unsigned char x, unsigned char y)
{
	// return MeggyFrame[24*x + y + 16]; 
	return(0);
}

unsigned char GetPixelG(unsigned char x, unsigned char y)
{
	//return MeggyFrame[24*x + y + 8]; 
	return(0);
}

unsigned char GetPixelB(unsigned char x, unsigned char y)
{
	//return MeggyFrame[24*x + y]; 
	return(0);
}

// Clear a single pixel.  Not much better than writing "dark" to the pixel.
void ClearPixel(unsigned char x, unsigned char y)
{
	
	/*
	 byte PixelPtr =  24*x + y;
	 MeggyFrame[PixelPtr] = 0;   
	 PixelPtr += 8;
	 MeggyFrame[PixelPtr] = 0;
	 PixelPtr += 8;
	 MeggyFrame[PixelPtr] = 0; 
	 */
}


// GetButtons returns a byte with a bit set for 
// each of the buttons that is currently pressed.


unsigned char GetButtons(void)
{
	int temp;
	temp = ~(PINC) & 0x3f;
	
	// HARDWARE TIMING 
	temp &= 0xdf;		// 1101 1111
	// bit 5 is an output used
	// for timing
	return(temp); 
}



// Set sound ON or OFF by calling
// SoundState(0) or SoundState(1).

//void SoundState(unsigned char t)
//

/*
 if ((t) && (SoundAllowed))
 { 
 
 //TCCR1A = 65;	// 0100 0001 
 //COM1A10 = 01 :  Toggle output OC1A on compare match.
 //WGM11,10: 01
 TCCR1A = 0x71;	// 0111 0001 
 
 
 TCCR1B = 0x11;	// 0001 0001  	// CS12..10 = 001: No clock prescaling. 
 
 // WGM13,12: 10
 // CS12,CS11,CS10: 001.  Count at CLKI/O/1 (no prescaling)
 
 //WGM: 1001, phase+frequency correct PWM
 // with top at OCR1A and update OCR1A at bottom.
 
 OCR1B = 0x1000;		// 0001 0000 0000 0000 
 
 
 SoundEnabled = 1;
 DDRB |= 0x02;		// 0000 0010 OC1A
 DDRB |= 0x04;		// 0000 0100 OC1B
 
 }
 else
 {
 SoundEnabled = 0;
 // TCCR1A = 0;	
 
 if (t)
 SoundEnabled = 0;
 
 //TCCR1B = 128;		// Harmless; can use (TCCR1B == 0) to check if sound is done.
 else
 //TCCR1B = 0; 	 
 //		DDRB &= 253;
 DDRB &= 0xfd;	// 1111 1101
 
 PORTB |= 2;
 }
 
 */


void clear_brightness_grid(void) {
	int i;
	
	for(i=0;i<8*(MAX_BRIGHTNESS+1)*3;i++) {
		brightness_grid[i]=0;
	}
}




/******************************************************************************
 * Constructor
 ******************************************************************************/


void ME218_Init() {
	_quick_ticks=0;
	
	
 	SUPER_MAGIC_CLUT_VARIABLE=&pgm_CLUT_Sequence[0];
  	SUPER_MAGIC_SPRITE_VARIABLE=&TIP_TOP_FIGHTERS[0];
  	SUPER_MAGIC_CITYWALL_VARIABLE=&city_walls_list[0];
  	SUPER_MAGIC_LED_VARIABLE=&pgm_LED_Sequence[0];

	
 	initializeCLUTs();
	initializeSPRITEs();
	initializeLEDs();
	
	// Initialization routine for Meggy Jr RGB hardware
	
	MIDI_shift=-1;
	MIDI_word=0;
	
	//locate_CITYWALL_data();
	
	sprite_smile=0;					
	
//	initializeSPRITEs();
//	initializeCLUTs();
	
	
	// brightness table refresh variables
	daisy_y=0;
	daisy_x=0;
	daisy_color=0;
	daisy_state=0;
	bright_index = 0;
	
	currentCol=0;
	currentBrightness=0;
	brightness_grid_index=0;
	clear_brightness_grid();
	
	Poor_Man=0;			// multitasking counter
	
	
	// Pull-ups on Port C  (for detecting button presses)
	DDRC = 0x0f;		// 0000 1111 
	// Pin 5: scope	Pin 4: MIDI
	PORTC |= 0x09;		// 0000 1001	- Start with MIDI high & red LED on proto board
	
	blinky_red_led=0;
	blinky_red_toggle=0;
	blinky_speed=4000;
	

	
	
	
	DDRD = 0xfe;		// All D Output except for Rx
	PORTD = 0xfe;		// 1111 1110
	
	DDRB = 0x3f;		// 0011 1111
	PORTB = 0xff;		// 1111 1111
	
	/* RICK always play sound
	 
	 
	 //If a button is pressed at startup, turn sound off.
	 if ((PINC & 63) != 63)
	 {
	 SoundAllowed = 0;
	 } 
	 else
	 {
	 SoundAllowed = 1;
	 } 
	 */
	SoundAllowed=1;
	
	SoundEnabled = 0;
	
	ToneTimeRemaining = 0;
	
	// Turn display off:
	
	PORTD |= 0xfc;	// 1111 1100
	
	PORTB |= 0x11;	// 0001 0001
	
	
	/*
	
	// ================== Timer 0 ===================
	TCCR0A = 0x41;	// 0100 0001 
	//COM1A10 = 01 :  Toggle output OC0A on compare match.
	//WGM11,10: 01
	
	TCCR0A = 0xa3;	// 1010 0011	
	
	TCCR0B = 0x0c;	// 0000 0001  	// CS12..10 = 001: No clock prescaling. 
	
	// WGM13,12: 10
	// CS12,CS11,CS10: 001.  Count at CLKI/O/1 (no prescaling)
	
	//WGM: 1001, phase+frequency correct PWM
	// with top at OCR1A and update OCR1A at bottom.
	
	OCR0A = 0x40;
	// ==================================================
	 */
	 
	 
	
	
	
	ClearMeggy();
	
	// Page 166, SPI2X is Double SPI Speed Bit
	// clocking at 2 mhz	
	SPSR = (1<<SPI2X); 
//	SPCR = 0; //turn off SPI
	SPCR = 0x50;		// 0101 0000 i.e., (1 << SPE) | ( 1 << MSTR );   

	
	// setup the interrupt.
	TCCR2A = (1<<WGM21); // clear timer on compare match
	
	// F_CPU >> 3 is 16,000,000 divided by 8. (clk/8 prescaler)
	// Page 154. Atmel 328P Preliminary 11/09
	
	TCCR2B = (1<<CS21); // timer uses main system clock with 1/8 prescale
	//	OCR2A  = (F_CPU >> 3) / 8 / 15 / FPS; // Frames per second * 15 passes for brightness * 8 rows
	// Reference clock is 2,000,000
	
	
	OCR2A = 64;				// MIDI speed 2,000,000 / 64 = 31,250 hz
	//	OCR2A = 138;			// 2,000,000 / 138 = 14,500 hertz
	
	TIMSK2 = (1<<OCIE2A);	// call interrupt on output compare match
	
	sei( );    // Enable interrupts
	
	
}







